package cur.nature.framework.mvc.tree;

import cur.nature.framework.core.util.JsonUtil;
import cur.nature.framework.core.util.ObjectUtil;
import cur.nature.framework.core.util.StringUtil;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.stream.Collectors;

public class TreeUtil {

    private static void insertNode(final TreeNode treeNode,final TreeNode parentNode){
        List<TreeNode> children = parentNode.getChildren();
        children = children==null?new ArrayList<>():children;
        children.add(treeNode);
        parentNode.setChildren(children);
    }

    //插入节点
    private static void processNode( final Map<String,TreeNode> allMap, final Map<String,TreeNode> missMap,
                            final TreeNode topNode, final TreeNode treeNode, final boolean processMis){
        //插入节点
        if(null==treeNode.getParentId()){
            //顶级节点
            insertNode(treeNode, topNode);
        }else{
            //其它节点
            TreeNode parent = allMap.get(treeNode.getParentId());
            if (parent != null) {
                insertNode(treeNode, parent);
            }else{
                //特殊情况，如果是处理未找到父节点的节点,则直接放到顶级节点
                if(processMis){
                    insertNode(treeNode, topNode);
                    return;
                }
                missMap.put(treeNode.getId(),treeNode);
            }
        }
    }

    //组装成树
    public static TreeNode packTree( final List<TreeNode> list, TreeNode topNode){
        if(list == null || list.size() == 0) {return null;}
        Map<String,TreeNode> allMap = new HashMap<>();
        Map<String,TreeNode> missMap = new HashMap<>();
        topNode = topNode == null? new TreeNode("0","顶级节点") : topNode;
        //1.拼接成树
        for (TreeNode treeNode : list) {
            //加入到allmap
            allMap.put(treeNode.getId(),treeNode);
            //插入节点
            processNode(allMap, missMap, topNode, treeNode, false);
        }
        //2.插入未找到父类的节点
        if(missMap.size()>0){
            for (TreeNode node : missMap.values()) {
                //插入节点
                processNode(allMap, missMap, topNode, node, true);
            }
        }
        //3.设置是否叶子节点
        for (TreeNode node : allMap.values()) {
            if(ObjectUtil.isNotEmpty(node.getChildren())){
                node.setLeaf(false);
            }
        }
        return topNode;
    }

    /**
     * 组装特殊树, 根据特殊节点id , 往上找父节点（无孩）, 往下找子节点(有孩)
     * @param list 源节点列表
     * @param topNode 顶级节点
     * @param specNodeList 选中节点列表
     * @return
     */
    public static TreeNode packSpecTree( List<TreeNode> list, TreeNode topNode, List<TreeNode> specNodeList){
        if(list == null || list.size() == 0 || ObjectUtils.isEmpty(specNodeList)) {return null;}
        topNode = topNode == null? new TreeNode("0","顶级节点") : topNode;

        Set<TreeNode> targetList = new HashSet<>();
        for (TreeNode specNode : specNodeList) {
            //向上找父节点
            insertParent(list, targetList, "0", specNode);
            //向下找子节点
            insertChildren(list, targetList, specNode);
        }
        //组装树
        packTree(new ArrayList<>(targetList), topNode);
        return topNode;
    }
    private static void insertParent(List<TreeNode> list, Set<TreeNode> targetList, String topNodeId, TreeNode specNode){
        if(!ObjectUtils.nullSafeEquals(topNodeId, specNode.getId())){
            targetList.add(specNode);
            // 如果parentnode 不是 topNode 的话,递归
            Optional<TreeNode> parentOpt = list.stream().filter(s -> ObjectUtils.nullSafeEquals(specNode.getParentId(), s.getId())).findFirst();
            TreeNode parentNode = parentOpt.isPresent() ? parentOpt.get() : new TreeNode();
            if(!ObjectUtils.nullSafeEquals(topNodeId, parentNode.getId()) && StringUtil.isNotEmpty(parentNode.getId())){
                insertParent(list,targetList, topNodeId, parentNode);
            }
        }
    }

    private static void insertChildren(List<TreeNode> list, Set<TreeNode> targetList, TreeNode specNode){
        List<TreeNode> childrenList = list.stream().filter(s->ObjectUtils.nullSafeEquals(s.getParentId(), specNode.getId())).collect(Collectors.toList());
        if(!ObjectUtils.isEmpty(childrenList)){
            for (TreeNode child : childrenList) {
                targetList.add(child);
                // 递归查找子节点
                insertChildren(list, targetList,child);
            }
        }
    }

    public static void main(String[] args) {
        List<TreeNode> treeNodeList = new ArrayList<>();
        for (int i = 1; i < 4; i++) {
            TreeNode treeNode = new TreeNode();
            treeNodeList.add(treeNode);
            treeNode.setId(i+"");
            treeNode.setText("节点: "+ i);
            if(i == 1 || i == 2){continue;}
            treeNode.setParentId(((i % 2) == 0)?"1":"2");
        }
//        TreeNode treeNode = TreeUtil.packTree(treeNodeList,null);
        for (int i = 5; i < 9; i++) {
            TreeNode treeNode = new TreeNode();
            treeNodeList.add(treeNode);
            treeNode.setId(i+"");
            treeNode.setText("AA节点: "+ i);
            treeNode.setParentId("2");
        }
        TreeNode treeNode = TreeUtil.packSpecTree(treeNodeList,null, Arrays.asList(treeNodeList.get(0), treeNodeList.get(5)));
        System.out.println(JsonUtil.toJSONString(treeNode));
    }

    public static List<TreeNode> finaAllChildren(List<TreeNode> allRoleTree, List<Integer> roleIdList, Boolean includeSelf) {
        List<TreeNode> resultList = new ArrayList<>();
        if(ObjectUtil.isNotEmpty(allRoleTree) && ObjectUtil.isNotEmpty(roleIdList)){
            for (Integer roleId : roleIdList) {
                // 如果包含自身，则查出自己并保存
                if(includeSelf){
                    List<TreeNode> selfList = allRoleTree.stream().filter(s -> ObjectUtil.equal(s.getId(), roleId+"")).collect(Collectors.toList());
                    resultList.addAll(selfList);
                }
                //查出parentId 等于 roleId 的所有节点, 并保存
                addChildren(allRoleTree, roleId+"", resultList);

            }
        }
        return resultList;
    }

    private static void addChildren(List<TreeNode> allRoleTree, String roleId, List<TreeNode> resultList){
        //查出parentId 等于 roleId 的所有节点, 并保存
        List<TreeNode> childrenList = allRoleTree.stream().filter(s -> ObjectUtil.equal(s.getParentId(), roleId)).collect(Collectors.toList());
        if(ObjectUtil.isNotEmpty(childrenList)){
            resultList.addAll(childrenList);
            //递归
            for (TreeNode child : childrenList) {
                addChildren(allRoleTree, child.getId(), resultList);
            }
        }



    }
}
